﻿namespace Sai.Core
{
    using Sai.Core.Reporting;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.IO;
    using System.Linq;
    using System.Xml.Serialization;

	[XmlRoot("ReleaseDifference")]
	public class ProductReleaseDifference : IProductReleaseDifference
	{
		private Identifier ident = new Identifier();

		private List<ProductAssembly> added = new List<ProductAssembly>();

		private List<ProductAssembly> changed = new List<ProductAssembly>();

		private List<ProductAssembly> removed = new List<ProductAssembly>();
		
		[XmlAttribute("ID")]
		public string Identifier
		{
			get
			{
				return this.ident.Value;
			}

			set
			{
				this.ident = new Identifier(value);
			}
		}

		[XmlAttribute("Name")]
		public string Name
		{
			get;
			set;
		}

		[XmlAttribute("From")]
		public string FromVersion
		{
			get;
			set;
		}

		[XmlAttribute("To")]
		public string ToVersion
		{
			get;
			set;
		}

		[XmlAttribute("ProductName")]
		public string ProductName
		{
			get;
			set;
		}

		[XmlAttribute("ProductLink")]
		public string ProductLink
		{
			get;
			set;
		}

		[XmlAttribute("ProductVersion")]
		public string ProductVersion
		{
			get;
			set;
		}

        [XmlAttribute("PercentChurn")]
        public int PercentChurn
        {
            get;
            set;
        }

        [XmlArray("AddedAssemblies", IsNullable = false)]
		[XmlArrayItem("Assembly", typeof(ProductAssembly))]
		public Collection<ProductAssembly> AddedAssemblies
		{
			get
			{
                if (this.added.Any())
                {
                    return new Collection<ProductAssembly>(this.added);
                }

                return null;
			}
		}

        [XmlArray("ChangedAssemblies", IsNullable = false)]
		[XmlArrayItem("Assembly", typeof(ProductAssembly))]
		public Collection<ProductAssembly> ChangedAssemblies
		{
			get
			{
                if (this.changed.Any())
                {
                    return new Collection<ProductAssembly>(this.changed);
                }

                return null;
			}
		}

		[XmlArray("RemovedAssemblies", IsNullable=false)]
		[XmlArrayItem("Assembly", typeof(ProductAssembly))]
		public Collection<ProductAssembly> RemovedAssemblies
		{
			get
			{
                if (this.removed.Any())
                {
                    return new Collection<ProductAssembly>(this.removed);
                }

                return null;
			}
		}

		public void Added(ProductAssembly assembly)
		{
			this.added.Add(assembly);
		}

		public void Changed(ProductAssembly assembly)
		{
			this.changed.Add(assembly);
		}

		public void Removed(ProductAssembly assembly)
		{
			this.removed.Add(assembly);
		}

		public ProductAssembly FindAssembly(string assemblyName)
		{
			ProductAssembly found = null;

			foreach (var assy in this.added)
			{
				if (assy.Name == assemblyName)
				{
					found = assy;
					break;
				}
			}

			if (found == null)
			{
				foreach (var assy in this.removed)
				{
					if (assy.Name == assemblyName)
					{
						found = assy;
						break;
					}
				}
			}

			if (found == null)
			{
				foreach (var assy in this.changed)
				{
					if (assy.Name == assemblyName)
					{
						found = assy;
						break;
					}
				}
			}

			return found;
		}

		public void SaveTo(string fileName)
		{
			using (var writer = new StreamWriter(fileName))
			{
				this.SaveTo(writer);
			}
		}

		public void SaveTo(TextWriter writer)
		{
            ObjectFlattener<ProductReleaseDifference>.Flatten(this, writer);
		}
		
		public string ToXml()
		{
			using (var writer = new StringWriter())
			{
				this.SaveTo(writer);
				return writer.ToString();
			}
		}
	}
}
